// Copyright (c) 2010 Omer Goshen
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "MudBath.h"
#include "EditorState.h"

//#include "managers/GnashManager.h"
//#include "utils/GnashUtils.h"

using namespace Ogre;
//using namespace MyGUI;
//using namespace CEGUI;

EditorState EditorState::mEditorState;

CEGUI::MouseButton convertButton(OIS::MouseButtonID buttonID)
{
	switch (buttonID)
		{
		case OIS::MB_Left:
			return CEGUI::LeftButton;

		case OIS::MB_Right:
			return CEGUI::RightButton;

		case OIS::MB_Middle:
			return CEGUI::MiddleButton;

		default:
			return CEGUI::LeftButton;
		}
}


/*
int getdir (string dir, std::vector<string> &files)
{
	DIR *dp;
	struct dirent *dirp;
	if ((dp = opendir(dir.c_str())) == NULL)
		{
			cout << "Error(" << errno << ") opening " << dir << endl;
			return errno;
		}

	while ((dirp = readdir(dp)) != NULL)
		{
			files.push_back(string(dirp->d_name));
		}
	closedir(dp);
	return 0;
}
*/

class SelectionRectangle : public ManualObject
{
public:
	SelectionRectangle(const Ogre::String &name)
		: ManualObject(name)
	{
		setUseIdentityProjection(true);
		setUseIdentityView(true);
		setRenderQueueGroup(RENDER_QUEUE_OVERLAY);
		setQueryFlags(0);
	}

	/**
	 * Sets the corners of the SelectionRectangle.  Every parameter should be in the
	 * range [0, 1] representing a percentage of the screen the SelectionRectangle
	 * should take up.
	 */
	void setCorners(float left, float top, float right, float bottom)
	{
		left = left * 2 - 1;
		right = right * 2 - 1;
		top = 1 - top * 2;
		bottom = 1 - bottom * 2;

		clear();
		begin("", RenderOperation::OT_LINE_STRIP);
		position(left, top, -1);
		position(right, top, -1);
		position(right, bottom, -1);
		position(left, bottom, -1);
		position(left, top, -1);
		end();

		AxisAlignedBox box;
		box.setInfinite();
		setBoundingBox(box);
	}

	void setCorners(const Vector2 &topLeft, const Vector2 &bottomRight)
	{
		setCorners(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
	}
};




//{{{ Starfield
class Starfield
{
public:
	Starfield()
	{
	}

	void CreateStarfield(Ogre::SceneManager* mSceneMgr, int NumberOfStars = 10000)
	{
		// Cria uma mesh manualmente
		ManualObject* manual = mSceneMgr->createManualObject("manual");

		manual->begin("BaseWhiteNoLighting", RenderOperation::OT_POINT_LIST);
		float brillance=0.0;
		Random p;
		for (int i=0; i<NumberOfStars; i++)
			{
				// Tamanho da esfera
				p.randomSphere(10000);
				brillance = (int)((float)rand()/32767*99);
				brillance = brillance/100;
				manual->position(p.PegaTabela(0), p.PegaTabela(1), p.PegaTabela(2));
				manual->colour(ColourValue(brillance, brillance, brillance, 1));
			}
		manual->end();

		// Agora cria um node e anexa a mesh manual criada
		mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual);
	}
};
//}}}

void createStarsField(Ogre::SceneManager*mSceneMgr = 0)
{
	Ogre::BillboardSet *StarsField = mSceneMgr->createBillboardSet("StarsField");
	SceneNode *node_StarsField = mSceneMgr->getRootSceneNode()->createChildSceneNode( "StarsField" );
	node_StarsField->attachObject( StarsField );
	StarsField->setMaterialName("Particle");
	Ogre::Billboard *StarsFieldBillboard[10000];
	int r = 8000;

	for (int i=0; i<10000; i++)
		{
			StarsFieldBillboard[i] = StarsField->createBillboard(r * sin(1+(int)((float)rand()/32767*99)) * sin(1+(int)((float)rand()/32767*99)),r * sin(1+(int)((float)rand()/32767*99)) * cos(1+(int)((float)rand()/32767*99)),r * cos(1+(int)((float)rand()/32767*99)));
			StarsFieldBillboard[i]->setDimensions(20,20);
		}


}



//{{{ EditorState
//{{{ enter
void EditorState::enter()
{
	cout << "+------------------------------+" << endl;
	cout << "|       Entring EditorState    |" << endl;
	cout << "+------------------------------+" << endl;

	///
	app = App::getSingletonPtr(); assert(app!=0);
	mRoot = Root::getSingletonPtr(); assert(mRoot!=0);
	mSceneMgr = app->getSceneManager(); assert(mSceneMgr!=0);


	/// Create Camera
	mCamera = mSceneMgr->createCamera("Camera");
	mCamera->setNearClipDistance(0.001);
	mCamera->setFarClipDistance(10000);
	mCamera->setDirection(Ogre::Vector3::NEGATIVE_UNIT_Z);
	App::getSingletonPtr()->setCamera(mCamera);

	///
	mWindow = mRoot->getAutoCreatedWindow();
	mViewport = mWindow->addViewport(mCamera);
	mViewport->setBackgroundColour(ColourValue::Black);
//	mViewport->setClearEveryFrame(true);

	mHUD = new HUD(mRoot, mSceneMgr, mCamera, mWindow);

	mSystem = new DeferredShadingSystem(mViewport, mSceneMgr, mCamera);
	mSystem->initialize();

	mViewportGrid = new ViewportGrid(mSceneMgr, mViewport);
	mViewportGrid->enable();

	mRect = new SelectionRectangle("SelectionRectangle");
	mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(mRect);
	mVolQuery = mSceneMgr->createPlaneBoundedVolumeQuery(PlaneBoundedVolumeList());
	mSelecting = false;


	const unsigned numShadowRTTs = mSceneMgr->getShadowTextureCount();
	for (unsigned i = 0; i < numShadowRTTs; ++i)
		{
			Ogre::TexturePtr tex = mSceneMgr->getShadowTexture(i);
			Ogre::Viewport *vp = tex->getBuffer()->getRenderTarget()->getViewport(0);
			vp->setBackgroundColour(Ogre::ColourValue(1, 1, 1, 1));
			vp->setClearEveryFrame(true);
		}

	// Selection buffer
	mSelectionBuffer = new SelectionBuffer(mSceneMgr, mCamera, mWindow);

//	cout << "--------------------- Starting Gnash ----------------------" << endl;
//	GnashManager::getSingletonPtr()->init();

	initGui();

//	SoundManager* soundMgr = SoundManager::createManager();
//	std::cout << soundMgr->listAvailableDevices();
//	soundMgr->init();
//	unsigned int audioId;
//	soundMgr->loadAudio( "test.wav", &audioId, false);
//	soundMgr->playAudio( audioId, true );

	createCameras();
	createScene();

	// do file, and simulate an ENTER press...
//	cout << "--------------------- init.lua ----------------------" << endl;
//	luaL_dofile( App::getSingletonPtr()->getLuaState(), "init.lua" );
//	Console* c = Console::getSingletonPtr();
//	c->print( c->getInterpreter()->getOutput() );
//	c->getInterpreter()->clearOutput();

	cout << "--------------------- init.js ----------------------" << endl;
	js_do_file(App::getSingletonPtr()->getContext(), "init.js");


	///TODO: why is this needed?
//	TransformWidget::getSingletonPtr()->hide();
	mTFW = TransformWidget::getSingletonPtr();
	mTFW->hide();

	mHUD->print("Scene Loaded...");

	mExitGame = false;
}
//}}}

//{{{ exit
void EditorState::exit()
{
//	Ogre::TextureManager::getSingleton().unload("RttTex");
	clearScene();


//	mGUI->shutdown();
//	delete mGUI;
//	mGUI = 0;
//	mPlatform->shutdown();
//	delete mPlatform;
//	mPlatform = 0;


	//!! Note: This is supposed to be mSceneMgr->destroyAllCameras(); for CVS head
	mRoot->getAutoCreatedWindow()->removeAllViewports();
}
//}}}

//{{{ pause
void EditorState::pause()
{
}
//}}}

//{{{ resume
void EditorState::resume()
{
}
//}}}

//{{{ frameStarted
bool EditorState::frameStarted(const FrameEvent& evt)
{
	return !mExitGame;

	/*
		mDebugText = StringConverter::toString(mWindow->getAverageFPS()) + "[FPS], " +
		             StringConverter::toString(App::getInstance().getFrameTime()) + "[ms], " +
		             StringConverter::toString(mWindow->getTriangleCount()) + "[Tris], " +
		             StringConverter::toString(mWindow->getBatchCount()) + "[Batches] "
		             ;
	*/
	mLastUpdate += evt.timeSinceLastFrame;
	if(mLastUpdate<0.25) return true;
	mLastUpdate = 0;

	App& app = App::getInstance();
	FrameTimes fs = app.getFrameStats();
	unsigned ft = app.getFrameTime();

#define FORMAT(x) setiosflags(ios::left) << setfill('0') << setw(5) << std::fixed << std::setprecision(2) << int((float(x) / float(ft)*100.f)*100)/100.f
	std::stringstream ss;
	ss << "Render: "  << FORMAT(fs.render)  << "% ";
	ss << "Script: "  << FORMAT(fs.script)  << "% ";
	ss << "Gui: "     << FORMAT(fs.gui)     << "% ";
	ss << "Physics: " << FORMAT(fs.physics) << "% ";

	mDebugText = ss.str() ;
//                "Render: "    + StringConverter::toString(float(fs.render)  / float(ft)*100.f, 3, 6, ' ') + "% " +
//                "Script: "    + StringConverter::toString(float(fs.script)  / float(ft)*100.f, 3, 6, ' ') + "% " +
//                "Gui: "       + StringConverter::toString(float(fs.gui)     / float(ft)*100.f, 3, 6, ' ') + "% " +
//                "Physics: "   + StringConverter::toString(float(fs.physics) / float(ft)*100.f, 3, 6, ' ') + "% " ;

	mDebugText2 =
	    "FrameTime: " + StringConverter::toString(ft) + "[ms] " +
	    StringConverter::toString(mWindow->getAverageFPS()) + "[FPS] " +
	    StringConverter::toString(mWindow->getTriangleCount()) + "[Tris] " +
	    StringConverter::toString(mWindow->getBatchCount()) + "[Batches] " +
	    "";

//	GnashManager::update();
//	GnashManager::blit();


//	if(mCamera==NULL) return true;
//	if(mCameraWindow->mWindow->getVisible())
//		{
//			mCameraWindow->getPosition()->setCaption(StringConverter::toString(mCamera->getDerivedPosition()));
//			mCameraWindow->getDirection()->setCaption(StringConverter::toString(mCamera->getDerivedDirection()));
//		}

	/*
		Ogre::Vector3 camDir = mCamera->getDerivedDirection();
		Ogre::Vector3 camPos = mCamera->getDerivedPosition();
		Radian fov = mCamera->getFOVy();
		Quaternion invCamOrient = mCamera->getDerivedOrientation().Inverse();
		Matrix4 invCamViewMat = mCamera->getViewMatrix(); invCamViewMat.inverse();

		Plane cameraPlane = Plane(camDir, mCamera->getNearClipDistance());
	//	Plane cameraPlane = Plane(camDir, camDir*mCamera->getNearClipDistance());

		Real screenX = 40.f;
		Real screenY = 560.f;
		Real screenWidth = mViewport->getActualWidth();
		Real screenHeight = mViewport->getActualHeight();

		Ray ray = mCamera->getCameraToViewportRay(screenX/screenWidth, screenY/screenHeight);

		std::pair< bool, Real> result = Math::intersects(ray, cameraPlane);
		if(!result.first) return true;
		Vector3 r = ray.getDirection()*result.second;

		Real d = (invCamOrient*(camPos - r)).length();

		mAxesNode->setOrientation(invCamOrient);
		mAxesNode->setScale(d/500.f*Vector3::UNIT_SCALE);
		mAxesNode->setPosition(invCamViewMat*r + invCamOrient*camPos);
	*/


	return !mExitGame;
}
//}}]

//{{{ frameEnded
bool EditorState::frameEnded(const FrameEvent& evt)
{
	return !mExitGame;
}
//}}}

//{{{ keyPressed
void EditorState::keyPressed( const OIS::KeyEvent &e )
{
//	if (mGUI->injectKeyPress(MyGUI::KeyCode::Enum(e.key), e.text)) return;
//	if (mGUI->injectKeyPress(MyGUI::KeyCode::Enum(e.key))) return;
//	if (MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(e.key))) return;

	CEGUI::System &sys = CEGUI::System::getSingleton();
	sys.injectKeyDown(e.key);
	sys.injectChar(e.text);

	if (mCamera->getParentSceneNode()==flyCam)
		flyCam->onKeyDown(e);

	OIS::Keyboard* keyb = App::getSingletonPtr()->getInputManager()->getKeyboard();
	if(keyb->isModifierDown(OIS::Keyboard::Ctrl))
		if(e.key==OIS::KC_E)
//			Console::getSingletonPtr()->print("Switched Edit Mode");
			mHUD->print("Switching Edit Mode");

	switch (e.key)
		{
//		case OIS::KC_RETURN:
//			OgreApplication::getSingletonPtr()->changeState(MenuState::getInstance());
//			break;
		case OIS::KC_NUMPAD1:
			mCamera->setDirection(Vector3::NEGATIVE_UNIT_Z);
			break;
		case OIS::KC_NUMPAD3:
			mCamera->setDirection(Vector3::NEGATIVE_UNIT_X);
			break;
		case OIS::KC_NUMPAD7:
			mCamera->setDirection(Vector3::NEGATIVE_UNIT_Y);
			orbitCam->setOrientation(Quaternion::IDENTITY);
			break;

		case OIS::KC_1:
			if(mCameraNode==NULL) break;
			mCamera->getParentSceneNode()->detachObject(mCamera);
			mCameraNode->attachObject(mCamera);
			mHUD->print("Camera #1");

			break;
		case OIS::KC_2:
			flyCam->attachCamera(mCamera);

			flyCam->freeLook = false;
			flyCam->useMouseButton = false;
			mHUD->print("Fly Camera (Locked view)");

			break;
		case OIS::KC_3:
			flyCam->attachCamera(mCamera);

			flyCam->freeLook = true;
			flyCam->useMouseButton = false;
			mHUD->print("Fly Camera (Always Look)");

			break;
		case OIS::KC_4:
			flyCam->attachCamera(mCamera, app->mCameraNode);

			flyCam->freeLook = true;
			flyCam->useMouseButton = true;

			mHUD->print("Fly Camera (LMB Look)");

			break;
		case OIS::KC_5:
			if(mCurrentNode==NULL || orbitCam->target==NULL)
				orbitCam->target = utils::SceneNodeUtils::createOrRetrieve(mSceneMgr, "Origin");

			mCamera->setOrientation(Quaternion::IDENTITY);
			orbitCam->attachCamera(mCamera, app->mCameraNode);
			mHUD->print("Orbit Camera");

			break;

		case OIS::KC_A:
			if(flyCam->getCamera()!=0) break;
			// Select all
			if(mSelectedObjects.empty())
				{
					GameObject* go;
					GameObject::ObjectIterator it = GameObject::getObjectsIterator();
					while(it.hasMoreElements())
						{
							go = it.getNext();
							if(go==0) continue;
//							TRACE(go->getName());
							mSelectedObjects.add(go);
//							if(!go->onSelected.empty())
//								go->onSelected();
						}
//					selectedObjectOverlay->setCaption(StringConverter::toString(mSelectedObjects.mObjects.size()) + " Objects selected");
				}
			// Deselect
			else
				{
					BaseGameObject* go;
					GameObjectGroup::GameObjectIterator it = mSelectedObjects.getObjectIterator();
					while(it.hasMoreElements())
						{
							go = dynamic_cast<GameObject*>(it.getNext());
							if(go->isNull()) continue;

//							if(!go->onDeselected.empty())
//								go->onDeselected();
						}
					mSelectedObjects.clear();

//					TransformWidget* tfw = TransformWidget::getSingletonPtr();
//					tfw->onReleased();
//					tfw->hide();
					if(mTFW!=0)
						{
							mTFW->onReleased();
							mTFW->hide();
						}

//					selectedObjectOverlay->setCaption(StringUtil::BLANK);
				}
			break;

		case OIS::KC_F:
			if(mCurrentNode==NULL) break;
			if(orbitCam->target==0) break;
			if(orbitCam->getCamera()==0) break;
			if(!orbitCam->isCameraAttached(mCamera)) break;

			orbitCam->mMove = true;
//			if(mCurrentNode->getAttachedObject(0)->getBoundingRadius()<1) break;
			orbitCam->mTargetPos =
			    orbitCam->getCamera()->getOrientation() * (Vector3::UNIT_Z *
			            mCurrentNode->getAttachedObject(0)->getBoundingRadius() * 5);

			break;
		case OIS::KC_G:
//			TransformWidget::getSingletonPtr()->setMode(TransformWidget::MOVE);
			mTFW->setMode(TransformWidget::MOVE);
			break;

		case OIS::KC_H:
			mHUD->toggle();
			break;

		case OIS::KC_S:
			if(flyCam->getCamera()!=0) break;

//			TransformWidget::getSingletonPtr()->setMode(TransformWidget::SCALE);
			mTFW->setMode(TransformWidget::SCALE);
			break;

		case OIS::KC_R:
//			TransformWidget::getSingletonPtr()->setMode(TransformWidget::ROTATE);
			mTFW->setMode(TransformWidget::ROTATE);
			break;

		case OIS::KC_W:
			if(flyCam->getCamera()!=0) break;
			if(mCamera->getPolygonMode()==PM_WIREFRAME)
				{
					mHUD->print("Solid Polygons");
					mCamera->setPolygonMode(PM_SOLID);
					break;
				}
			if(mCamera->getPolygonMode()==PM_SOLID)
				{
					mHUD->print("Wireframe Polygons");
					mCamera->setPolygonMode(PM_WIREFRAME);
					break;
				}

			break;

		case OIS::KC_O:
		case OIS::KC_NUMPAD5:
			if(mCamera->getProjectionType()==Ogre::PT_ORTHOGRAPHIC)
				{
					mHUD->print("Perspective Projection");
					mCamera->setProjectionType(Ogre::PT_PERSPECTIVE);
					break;
				}
			if(mCamera->getProjectionType()==Ogre::PT_PERSPECTIVE)
				{
					mHUD->print("Orthographic Projection");
					mCamera->setProjectionType(Ogre::PT_ORTHOGRAPHIC);
					break;
				}
			break;

		case OIS::KC_T:
			GameLight::mShowDebug = !GameLight::mShowDebug;
			mHUD->print(string("Lights Debug ")+(GameLight::mShowDebug?"On":"Off"));
			break;

		case OIS::KC_V:
			mViewportGrid->toggle();
			mHUD->print(string("Grid ")+(mViewportGrid->isEnabled()?"On":"Off"));
			break;

		case OIS::KC_Z:
			App::getInstance().togglePhysics();
			mHUD->print(string("Physics ")+(App::getInstance().getPhysicsActive()?"On":"Off"));
			break;

		case OIS::KC_F1:
			mSystem->setActive(false);
			mViewport->setMaterialScheme("Low");
			mHUD->print("Low Quality");
			break;

		case OIS::KC_F2:
			mSystem->setActive(false);
			mViewport->setMaterialScheme("Medium");
			mHUD->print("Medium Quality");
			break;

		case OIS::KC_F3:
			mSystem->setActive(true);
			mViewport->setMaterialScheme(Ogre::MaterialManager::DEFAULT_SCHEME_NAME);
			mHUD->print("High Quality");
			break;

		case OIS::KC_B:
			mSelecting = true;
			break;

		case OIS::KC_N:
			mSystem->setMode(DeferredShadingSystem::DSM_SHOWNORMALS);
			mHUD->print("Showing Normals");
			break;

		case OIS::KC_P:
			mSystem->setMode(DeferredShadingSystem::DSM_SHOWDSP);
			mHUD->print("Showing Depth\\Specular");
			break;

		case OIS::KC_C:
			mSystem->setMode(DeferredShadingSystem::DSM_SHOWCOLOUR);
			mHUD->print("Showing Color");
			break;

		case OIS::KC_L:
			mSystem->setMode(DeferredShadingSystem::DSM_SHOWLIT);
			mHUD->print("Showing Lit");
			break;

		case OIS::KC_X:
			App::getInstance().toggleDebug();
			mHUD->print(string("Physics Debug ")+(App::getInstance().getShowDebug()?"On":"Off"));
			break;

		default:
			break;
		}
}
//}}}

//{{{ keyReleased
void EditorState::keyReleased( const OIS::KeyEvent &e )
{
	if ( e.key == OIS::KC_ESCAPE )
		{
			mExitGame = true;
			App::getInstance().quit();
			return;
		}
	
	mSelecting = false;
	
	CEGUI::System::getSingleton().injectKeyUp(e.key);
//	if (mGUI->injectKeyRelease(MyGUI::KeyCode::Enum(e.key))) return;
//	if (MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(e.key))) return;

	if (mCamera->getParentSceneNode()==flyCam)
		flyCam->onKeyUp(e);
}
//}}}

//{{{ mouseMoved
void EditorState::mouseMoved( const OIS::MouseEvent &e )
{
	const OIS::MouseState& ms = e.state;


	CEGUI::System &sys = CEGUI::System::getSingleton();
//	Real f = Math::Exp(2);
//	sys.injectMouseMove(f*ms.X.rel, f*ms.Y.rel);
	sys.injectMousePosition(ms.X.abs, ms.Y.abs);

	if (ms.Z.rel)
		sys.injectMouseWheelChange(ms.Z.rel / 120.0f);
//    cegui.injectMouseWheelChange(e.state.Z.rel * 0.03);

	if(mSelecting)
		{
			mStop = Vector2(ms.X.abs / (float)ms.width, ms.Y.abs / (float)ms.height);
			mRect->setCorners(mStart, mStop);
		}

//	TransformWidget::getSingletonPtr()->onMouseMove(e);
	mTFW->onMouseMove(e);

	if(TransformWidget::isTransforming()) return;

//	OIS::Keyboard* keyb = OgreApplication::getSingletonPtr()->getInputManager()->getKeyboard();

////	if(mGUI->injectMouseMove(ms.X.abs, ms.Y.abs, ms.Z.abs))
//	if(MyGUI::InputManager::getInstance().injectMouseMove(ms.X.abs, ms.Y.abs, ms.Z.abs))
//		if(!ms.buttonDown(OIS::MB_Middle) ||
//		        (ms.buttonDown(OIS::MB_Left) &&
//		         (keyb->isModifierDown(OIS::Keyboard::Alt) ||
//		          keyb->isModifierDown(OIS::Keyboard::Shift)))
//		  ) return;

//	if (keyb->isModifierDown(OIS::Keyboard::Alt)) return;

	if (flyCam && mCamera->getParentSceneNode()==flyCam)
		flyCam->onMouseMove(e);

	if (orbitCam && mCamera->getParentSceneNode()==orbitCam)
		orbitCam->onMouseMove(e);

//	if (mGUI->injectMouseMove(ms.X.abs, ms.Y.abs, ms.Z.abs)) return;
//	if (TransformWidget::isTransforming()) return;
}
//}}}

//{{{ mousePressed
void EditorState::mousePressed( const OIS::MouseEvent &e, OIS::MouseButtonID id )
{
	const OIS::MouseState ms = e.state;

	CEGUI::System::getSingleton().injectMouseButtonDown(convertButton(id));

	mStart = Vector2(ms.X.abs/(float)ms.width, ms.Y.abs/(float)ms.height);
	mRect->clear();
	mRect->setVisible(true);

	orbitCam->onMousePress(e);

	OIS::Keyboard* keyb = App::getSingletonPtr()->getInputManager()->getKeyboard();
//	if (keyb->isModifierDown(OIS::Keyboard::Alt) || keyb->isModifierDown(OIS::Keyboard::Shift)) return;
	if (keyb->isModifierDown(OIS::Keyboard::Alt)) return;


	if(ms.buttonDown(OIS::MB_Middle)) return;

	SceneNode* oldNode = mCurrentNode;

	Ogre::Entity* selectedEntity = mSelectionBuffer->OnSelectionClick(ms.X.abs, ms.Y.abs);
	if (!selectedEntity)
		{
			mTFW->hide();

			if(mOldObject)
				prop_cast<bool>((*mOldObject)["showOBBox"])->Set(false);

			GameObjectGroup::GameObjectIterator it = mSelectedObjects.getObjectIterator();
			while(it.hasMoreElements())
				{
					GameObject* go = dynamic_cast<GameObject*>(it.getNext());
					if(go==NULL) continue;

					prop_cast<bool>((*go)["showOBBox"])->Set(false);

				}
			mSelectedObjects.clear();
			mOldObject = 0;
			mCurrentNode = 0;
			return;
		}

	mCurrentNode = selectedEntity->getParentSceneNode();

	//!TODO: use something different maybe...
	if (mCurrentNode->getParentSceneNode())
		{
			if (mCurrentNode->getParentSceneNode()->getName()=="TransformWidget")
				{
					mTFW->onEntityPressed(selectedEntity);
					mCurrentNode = oldNode;
					mTFW->mTransNode = mCurrentNode;
				}
		}

	if (mCurrentNode==oldNode) return;
	mOldObject = mCurrentObject;


	orbitCam->mMove = false;


	UserObjectBindings& uob = selectedEntity->getUserObjectBindings();
	Ogre::Any any = uob.getUserAny();
	if(any.getType()==typeid(NULL) || any.isEmpty()) return;

	BaseGameObject* go = any_cast<BaseGameObject*>(any);
	assert(go);
	mCurrentObject = go;

	if(!keyb->isModifierDown(OIS::Keyboard::Shift))
		{
			BaseGameObject* go;
			GameObjectGroup::GameObjectIterator it = mSelectedObjects.getObjectIterator();
			while(it.hasMoreElements())
				{
					go = dynamic_cast<GameObject*>(it.getNext());
					if(go==NULL) continue;

					prop_cast<bool>((*go)["showOBBox"])->Set(false);

				}
			mSelectedObjects.clear();
		}

	mSelectedObjects.add(go);

	onObjectSelected();



/// TODO: hmmm...
	mSelectionBuffer->clearBlackList();
	for (std::vector<Entity*>::iterator it=mTFW->mEntities.begin(); it!=mTFW->mEntities.end(); ++it)
		{
			Entity* ent = static_cast<Entity*>(*it);
			Ogre::Renderable* r = static_cast<Renderable*>(ent->getSubEntity(0));
			mSelectionBuffer->pushToBlackList(r);
		}

	if (mCurrentObject && orbitCam->getCamera()!=0)
		{
			orbitCam->target = go->getProperty<SceneNode*>("scenenode");
			orbitCam->update();
		}
}
//}}}

//{{{ mouseReleased
void EditorState::mouseReleased( const OIS::MouseEvent &e, OIS::MouseButtonID id )
{
	const OIS::MouseState ms = e.state;

	CEGUI::System::getSingleton().injectMouseButtonUp(convertButton(id));

//	mGUI->injectMouseRelease(ms.X.abs, ms.Y.abs, MyGUI::MouseButton::Enum(id));
//	if(MyGUI::InputManager::getInstance().injectMouseRelease(ms.X.abs, ms.Y.abs, MyGUI::MouseButton::Enum(id))) return;
	mRect->setVisible(false);


	if (mTFW->isTransforming())
		{
			mTFW->onReleased();
//			MyGUI::PointerManager::getInstance().setVisible(true);
//			if (mPhysicsActive)	tfw->hide();

		}

	orbitCam->onMouseRelease(e);
}
//}}}

//{{{ initGui
void EditorState::initGui()
{
	// CEGUI
	CEGUI::OgreRenderer& renderer = CEGUI::OgreRenderer::create();
	renderer.setRenderingEnabled(false);

	lua_State* L = App::getSingletonPtr()->getLuaState();
//	CEGUI::LuaScriptModule& script_module = CEGUI::LuaScriptModule::create(L);

	CEGUI::OgreResourceProvider* res_prov = &renderer.createOgreResourceProvider();

//	Ogre::ResourceGroupManager& rgm = Ogre::ResourceGroupManager::getSingleton();
//    rgm.addResourceLocation("Media/CEGUI_Media/fonts/", "FileSystem", "fonts");

//	new CEGUI::System( renderer, 0, 0, 0, script_module );
//	CEGUI::System::create(renderer, res_prov, 0, 0, &script_module, "", "CEGUI.log");
	CEGUI::System::create(renderer, res_prov, 0, 0, 0, "", "CEGUI.log");

	// setup required to do direct rendering of FPS value
	const CEGUI::Rect scrn(CEGUI::Vector2(0, 0), renderer.getDisplaySize());
	mFPSGeometry = &renderer.createGeometryBuffer();
	mFPSGeometry->setClippingRegion(scrn);

	// clearing this queue actually makes sure it's created(!)
	renderer.getDefaultRenderingRoot().clearGeometry(CEGUI::RQ_OVERLAY);

	// subscribe handler to render overlay items

	renderer.getDefaultRenderingRoot().
	subscribeEvent(CEGUI::RenderingSurface::EventRenderQueueStarted,
	               CEGUI::Event::Subscriber(
	                   &EditorState::OverlayHandler, this));



	try
		{
			CEGUI::System::getSingleton().executeScriptFile("demo8.lua");
		}
	catch(CEGUI::ScriptException& e)
		{
			std::cout << e.what() << std::endl;
		}

	/*
		/// MyGUI
		/// TODO: same, but width script...
		Console::getSingletonPtr()->print("*** Initializing MyGUI ***");

		OverlayManager::getSingleton().destroy(OverlayManager::getSingleton().getByName("Core/LoadOverlay"));
		OverlayManager::getSingleton().destroy(OverlayManager::getSingleton().getByName("Core/DebugOverlay"));

		mPlatform = new MyGUI::OgrePlatform();
		mPlatform->initialise(mWindow, mSceneMgr);

		mGUI = new MyGUI::Gui();
		mGUI->initialise();

	//	MyGUI::LogManager::setSTDOutputEnabled(false);

		MyGUI::LanguageManager::getInstance().loadUserTags("core_theme_black_blue_tag.xml");
		MyGUI::ResourceManager::getInstance().load("core_skin.xml");

	//	MyGUI::MenuBar * a_pMenuBar = mGUI->createWidget<MyGUI::MenuBar>("MenuBar", 0, 0, mGUI->getViewWidth(), 25, MyGUI::Align::Default, "Overlapped");
		MyGUI::MenuBar * a_pMenuBar = mGUI->createWidget<MyGUI::MenuBar>("MenuBar", 0, 0, mWindow->getWidth(), 25, MyGUI::Align::Default, "Overlapped");

		MyGUI::MenuItem * a_pFileItem = a_pMenuBar->addItem("File", MyGUI::MenuItemType::Popup);
		MyGUI::PopupMenu * a_pPopupMenu = a_pFileItem->createItemChildT<MyGUI::PopupMenu>();
		a_pPopupMenu->addItem("New");
		a_pPopupMenu->eventMenuCtrlAccept = MyGUI::newDelegate(mousePressedMenuItem);
		a_pPopupMenu->addItem("Open");
		a_pPopupMenu->eventMenuCtrlAccept = MyGUI::newDelegate(mousePressedMenuItem);
		a_pPopupMenu->addItem("",MyGUI::MenuItemType::Separator);
		a_pPopupMenu->addItem("Quit");
		a_pPopupMenu->eventMenuCtrlAccept = MyGUI::newDelegate(mousePressedMenuItem);

		a_pFileItem = a_pMenuBar->addItem("Windows", MyGUI::MenuItemType::Popup);
		a_pPopupMenu = a_pFileItem->createItemChildT<MyGUI::PopupMenu>();
		a_pPopupMenu->addItem("Camera");
		a_pPopupMenu->addItem("Rendering");
		a_pPopupMenu->addItem("Physics");
		a_pPopupMenu->addItem("NewObject");

		a_pPopupMenu->eventMenuCtrlAccept = MyGUI::newDelegate(mousePressedMenuItem);

		mNewGOWindow = new NewGameObjectWindow();
		mCameraWindow = new CameraWindow();
		mRenderWindow = new RenderingWindow();
		mPhysicsWindow = new PhysicsWindow();
		mObjectWindow = new ObjectWindow();

		mOpenSaveFileDialog = new common::OpenSaveFileDialog();
		mOpenSaveFileDialog->setVisible(false);
	//	mOpenSaveFileDialog->setFileMask("*.xml");
		mOpenSaveFileDialog->setFileMask(L"*.xml");
		mOpenSaveFileDialog->eventEndDialog = MyGUI::newDelegate(EditorGui::notifyOpenSaveEndDialog);

		CompositorManager &compMan = CompositorManager::getSingleton();
		compMan.addCompositor(mViewport, "Bloom");
	//	compMan.addCompositor(mViewport, "HDR", 0);

		//{{{ Toolbar
		MyGUI::ButtonPtr button = mGUI->createWidget<MyGUI::Button>("Button", 0, 24, 48, 48, MyGUI::Align::Default, "Overlapped", "Move");
		button->setCaption("Move");
		button->eventMouseButtonClick = MyGUI::newDelegate(EditorGui::buttonClickCallBack);

		button = mGUI->createWidget<MyGUI::Button>("Button", 48, 24, 48, 48, MyGUI::Align::Default, "Overlapped", "Rotate");
		button->setCaption("Rotate");
		button->eventMouseButtonClick = MyGUI::newDelegate(EditorGui::buttonClickCallBack);

		button = mGUI->createWidget<MyGUI::Button>("Button", 96, 24, 48, 48, MyGUI::Align::Default, "Overlapped", "Scale");
		button->setCaption("Scale");
		button->eventMouseButtonClick = MyGUI::newDelegate(EditorGui::buttonClickCallBack);

		MyGUI::ComboBoxPtr combo = mGUI->createWidget<MyGUI::ComboBox>("ComboBox", 144, 24, 72, 48, MyGUI::Align::Default, "Overlapped", "TransfromSpace");
		combo->setComboModeDrop(true);
		combo->addItem("World");
		combo->addItem("Local");
		combo->addItem("View");
		combo->setIndexSelected(0);
		combo->eventComboChangePosition = newDelegate(EditorGui::comboChanged);


		combo = mGUI->createWidget<MyGUI::ComboBox>("ComboBox", 216, 24, 96, 48, MyGUI::Align::Default, "Overlapped", "Pivot");
		combo->setComboModeDrop(true);
		combo->addItem("Individual");
		combo->addItem("Median");
		combo->setIndexSelected(0);
		combo->eventComboChangePosition = newDelegate(EditorGui::comboChanged);
		//}}}

		MyGUI::StaticImage* hud = mGUI->createWidget<MyGUI::StaticImage>("StaticImage", 0, 0, mViewport->getActualWidth(), mViewport->getActualHeight(), MyGUI::Align::Default, "Back", "HUD");
		hud->setImageTexture("HudTex");
		hud->setEnabled(false);
	//	hud->setAlpha(.5f);

	//	MyGUI::StaticImage* gnash = mGUI->createWidget<MyGUI::StaticImage>("StaticImage",0,0,mViewport->getActualWidth(),mViewport->getActualHeight(),MyGUI::Align::Default, "Back", "gnashImage");
	//	gnash->setImageTexture("gnashTex");
	//	gnash->setEnabled(true);


	//	const MyGUI::IntSize size(320, 200);
	//	MyGUI::Window* window = mGUI->createWidget<MyGUI::Window>("WindowCSX", 20, 500 , size.width, size.height, MyGUI::Align::Default, "Overlapped", "RTT");
	//	window->setCaption("RTT");
	//	MyGUI::StaticImage* img = window->createWidget<MyGUI::StaticImage>("StaticImage", 0, 0, size.width, size.height, MyGUI::Align::Default, "RTT_StaticImg");
	//	img->setImageTexture("SelectionPassTex");
	*/
}
//}}}

//{{{ createCameras
void EditorState::createCameras()
{
	// Cameras
	flyCam = new FlyCamera(mSceneMgr);
	flyCam->setPosition(Ogre::Vector3(0,5,20));
	flyCam->mMove = 0.005f;
	mRoot->addFrameListener(flyCam);

	orbitCam = new OrbitCamera(mSceneMgr);
	orbitCam->setPosition(Ogre::Vector3(0,5,20));
	orbitCam->target = mSceneMgr->getRootSceneNode();
	mRoot->addFrameListener(orbitCam);

	orbitCam->attachCamera(mCamera);
}
//}}}

//{{{ createScene
void EditorState::createScene()
{
	// Ambient
	mSceneMgr->setAmbientLight(.25f*ColourValue::White);

	// Sun
	Ogre::Light* directionalLight = mSceneMgr->createLight("DirectionalLight1");
	directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
	directionalLight->setDiffuseColour(Ogre::ColourValue(.1, .07, .1));
	directionalLight->setSpecularColour(Ogre::ColourValue(.02, .02, .01));
	directionalLight->setDirection(Ogre::Vector3( 1, -1, 1 ));
	directionalLight->setSpecularColour(ColourValue(.5,.5,.5,1));
	directionalLight->setCastShadows(true);

	// a bluish backlight
	directionalLight = mSceneMgr->createLight("DirectionalLight2");
	directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
	directionalLight->setDiffuseColour(Ogre::ColourValue(.05, .03, .1));
	directionalLight->setSpecularColour(Ogre::ColourValue(.04, .04, .13));
	directionalLight->setDirection(Ogre::Vector3( -1, 1, -1 ));
	directionalLight->setCastShadows(false);

	// and a final touch
	directionalLight = mSceneMgr->createLight("DirectionalLight3");
	directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
	directionalLight->setDiffuseColour(Ogre::ColourValue(.05, .03, .04));
	directionalLight->setSpecularColour(Ogre::ColourValue(.05, .04, .04));
	directionalLight->setDirection(Ogre::Vector3( -1, -1, -1 ));
	directionalLight->setCastShadows(false);

//	// Plane
//	Ogre::Plane plane;
//	plane.normal = Ogre::Vector3::UNIT_Y;
//	plane.d = 0;
//	Ogre::MeshManager::getSingleton().createPlane("Myplane",
//	        Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
//	        1500, 1500, 1, 1, true, 1, 75, 75, Ogre::Vector3::UNIT_Z);
//
//	GameObject* planeGo = new GameObject("Plane");
//	planeGo->addComponent(new TransformComponent(planeGo, "TransformComponentInstance"));
//	planeGo->addComponent(new RenderComponent(planeGo, "Plane", "Myplane"));
//	planeGo->addComponent(new PhysicsComponent(App::getInstance().getDynWorld(), planeGo, 0));
//
//	Entity* ent = planeGo->getProperty<Entity*>("entity");
//	ent->setCastShadows(false);
//	ent->getMesh()->buildTangentVectors();
//	ent->setMaterialName("Grid");
////	ent->setMaterialName("Grid4");

	// Starfield
//	createStarsField(mSceneMgr);
//	Starfield *p_Starfield = new Starfield();
//	p_Starfield->CreateStarfield(mSceneMgr);
}
//}}}

//{{{ clearScene
void EditorState::clearScene()
{
//	mRoot->removeFrameListener(flyCam);
//	mRoot->removeFrameListener(orbitCam);

	delete flyCam;
	delete orbitCam;

	mSceneMgr->clearScene();

//	createScene();
}
//}}}
//}}}

void EditorState::onObjectSelected()
{
	if(mSelectedObjects.empty()) return;

	BaseGameObject* go = mSelectedObjects.mObjects.back();
	if(go==NULL) return;

	prop_cast<bool>((*go)["showOBBox"])->Set(true);

//	TRACE(go->getXmlString());

	mTFW->show();
	mTFW->mGo = go;
	mTFW->mGroup = mSelectedObjects;

	TransformWidget::setTransforming(true);

//	SceneNode* node = go->getProperty<SceneNode*>("scenenode");
//	SceneNodeUtils::RecursiveSetBoundingBox(node, true);

//	lua_getglobal(L, "Editor");
}

bool EditorState::OverlayHandler(const CEGUI::EventArgs& args)
{
	using namespace CEGUI;

	if (static_cast<const RenderQueueEventArgs&>(args).queueID != RQ_OVERLAY)
		return false;

	// render FPS:
	CEGUI::Font* fnt = CEGUI::System::getSingleton().getDefaultFont();
	fnt->setAutoScaled(false);

	if (fnt)
		{
			mFPSGeometry->reset();

			int H = mViewport->getActualHeight() - 30;
			CEGUI::Vector2 pos(0,H);
			CEGUI::Vector2 offset(1,1);

			fnt->drawText(*mFPSGeometry, mDebugText,
			              pos + offset,
			              0,
			              CEGUI::colour(0xCC000000));

			fnt->drawText(*mFPSGeometry, mDebugText,
			              CEGUI::Vector2(0, H),
			              0,
			              CEGUI::colour(0xFFFFFFFF));


			fnt->drawText(*mFPSGeometry, mDebugText2,
			              pos + CEGUI::Vector2(0,15) + offset,
			              0,
			              CEGUI::colour(0xCC000000));

			fnt->drawText(*mFPSGeometry, mDebugText2,
			              CEGUI::Vector2(0, H + 15),
			              0,
			              CEGUI::colour(0xFFFFFFFF));

			mFPSGeometry->draw();
		}

	return true;
}
